package cn.bugstack.springframework.beans.factory.support;

import java.lang.reflect.Constructor;

import cn.bugstack.springframework.BeanException;
import cn.bugstack.springframework.PropertyValue;
import cn.bugstack.springframework.PropertyValues;
import cn.bugstack.springframework.beans.factory.config.BeanDefinition;
import cn.bugstack.springframework.beans.factory.config.BeanReference;
import cn.hutool.core.bean.BeanUtil;

/**
 * description: 实例化Bean
 * taskId：
 * <pre>
 * change history:
 * date             defect#             person                comments
 * ---------------------------------------------------------------------
 * 2024/12/31       ********         zhaochaoyue        create file
 * </pre>
 *
 * @author: zhaochaoyue
 * @date: 2024/12/31 15:37
 * @copyright: 2024
 */
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory{
    
    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    @Override
    protected Object createBean(String name, BeanDefinition beanDefinition, Object[] args) {
        Object bean;
        try {
            bean = createBeanInstance(name,beanDefinition,args);
            //给bean添加属性
            applyPropertyValues(name,bean,beanDefinition);
        } catch (Exception e) {
            throw new BeanException("Instantiation of bean failed",e);
        }

        addSingleton(name,bean);
        return bean;
    }

    protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
        PropertyValues propertyValues = beanDefinition.getPropertyValues();
        try {
            for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
                String name = propertyValue.getName();
                Object value = propertyValue.getValue();
                if(value instanceof BeanReference){
                    //A依赖B获取B的实例
                    BeanReference beanReference = (BeanReference)value;
                    value = getBean(beanReference.getBeanName());
                }
                //属性设置值
                BeanUtil.setFieldValue(bean,name,value);
            }
        }catch (Exception e){
            throw  new BeanException("Error setting property values:"+beanName);
        }
    }

    private Object createBeanInstance(String name, BeanDefinition beanDefinition, Object[] args) {
        Constructor constructorToUse = null;
        Class<?> beanClass = beanDefinition.getBeanClass();
        Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
        for (Constructor ctor : declaredConstructors) {
            if(args !=null && ctor.getParameterTypes().length == args.length){
                constructorToUse = ctor;
                break;
            }
        }
        return getInstantiationStrategy().instantiate(beanDefinition,name,constructorToUse,args);
    }

    public InstantiationStrategy getInstantiationStrategy() {
        return instantiationStrategy;
    }

    public void setInstantiationStrategy(
        InstantiationStrategy instantiationStrategy) {
        this.instantiationStrategy = instantiationStrategy;
    }
}
